package com.xbongbong.paas.toolbox.helper;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.i18n.util.I18nMessageUtil;
import com.xbongbong.paas.constant.ConfigConstant;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.OkHttpUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.pro.constant.I18nStringConstant;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.saas.constant.StringConstant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * 高德地图帮助类
 * Created by kaka on 2018/5/2 0002.
 * @author kaka， modifyed by zheng.li
 */
public class GaodeGeoHelper {

    private static final Logger LOG = LoggerFactory.getLogger(GaodeGeoHelper.class);

    private static final String GAODE_GEO_URL = "http://restapi.amap.com/v3/geocode/geo";
    private static final String GAODE_REGEO_URL = "http://restapi.amap.com/v3/geocode/regeo";
    private static final String GAODE_DISTRICT_URL = "https://restapi.amap.com/v3/config/district";

    /**
     * 通过高德restful api将详细地址信息转化为经纬度
     * @param address 详细地址
     * @param city 详细地址所在城市，为增加转换准确度
     * @param output 输出格式
     * @return 返回一个json
     *
     * @author kaka
     * @date 2018-5-2
     * @since v3.21
     */
    public static JSONObject geo(String address, String city, String output) throws XbbException {
        Map<String, Object> geoParam = new HashMap<>();
        geoParam.put("key", ConfigConstant.GAODE_WEB_API_KEY);
        geoParam.put("address", address);
        geoParam.put("city", city);
        geoParam.put("output", output);

        String respStr = OkHttpUtil.get(GAODE_GEO_URL, geoParam);
        LOG.info("=====respStr=====" + respStr);
        JSONObject respJson;
        try {
            respJson = JSON.parseObject(respStr);
        } catch (Exception e) {
            LOG.error("高德地图geo接口返回数据解析错误", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100080);
        }

        LOG.info("请求高德地图的返回信息（request gaode info）" + respJson);
        if(respJson == null) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100043);
        }
        String status = respJson.getString("status");
        if(Objects.equals(status, "1")) {
            //成功
            JSONArray geocodes = respJson.getJSONArray("geocodes");
            if(geocodes != null && geocodes.size() > 0) {
                JSONObject geo = geocodes.getJSONObject(0);
                String location = geo.getString("location");
                String[] jinwei = location.split(",");
                if(jinwei.length == 2) {
                    double longitude = Double.parseDouble(jinwei[0]);
                    double latitude = Double.parseDouble(jinwei[1]);

                    /******* 经纬度判断 start 经纬度 *******/
                    //经纬度超出范围时：经度使用最大值180度,纬度使用最大90度或最小值-90度
                    longitude = (longitude >= 180D || longitude <= -180D) ? 180D : longitude;
                    latitude = (latitude >= 90D) ? 90D : (latitude <= -90D) ? -90D : latitude;
                    /******* 经纬度判断 end *******/
                    // 地址必须返回5个字段，保存接口和es会校验。校验不通过会报错
                    JSONObject result = new JSONObject();
                    result.put("longitude",longitude);
                    result.put("latitude",latitude);
                    result.put("province",geo.getString("province"));
                    result.put("city",geo.getString("city"));
                    // 高德地图针对未查到的district返回的数据为[]空数组，可查到的返回字符串
                    Object district = geo.get("district");
                    if (district instanceof String) {
                        result.put("district", String.valueOf(district));
                    } else {
                        result.put("district", "");
                    }
                    return result;
                } else {
                    throw new XbbException(SystemErrorCodeEnum.API_ERROR_100080);
                }

            }

        } else {
            String info = respJson.getString("info");
            String msg = I18nMessageUtil.getMessage(I18nStringConstant.GAO_ERROR);
            if(!StringUtil.isEmpty(info)) {
                msg += info;
            }
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100043, msg);
        }

        return null;
    }

    /**
     * 通过高德restful api将经纬度转化为详细地址信息
     *
     * @param longitude 经度
     * @param latitude 纬度
     *
     * @return 地址json
     * @author hongxiao
     * @date 2020-10-23 16:07
     */
    public static JSONObject regeo(Double longitude, Double latitude) throws XbbException {
        String location = longitude.toString() + StringConstant.COMMA + latitude.toString();
        Map<String, Object> geoParam = new HashMap<>();
        geoParam.put("key", ConfigConstant.GAODE_WEB_API_KEY);
        geoParam.put("location", location);
        geoParam.put("output", "JSON");

        String respStr = OkHttpUtil.get(GAODE_REGEO_URL, geoParam);
        LOG.info("=====respStr=====" + respStr);
        JSONObject respJson;
        try {
            respJson = JSON.parseObject(respStr);
        } catch (Exception e) {
            LOG.error("高德地图geo接口返回数据解析错误", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100080);
        }

        LOG.info("请求高德地图的返回信息（request gaode info）" + respJson);
        if(respJson == null) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100043);
        }
        String status = respJson.getString("status");
        if(Objects.equals(status, "1")) {
            //成功
            JSONObject regeocodes = respJson.getJSONObject("regeocode");
            if(regeocodes != null) {
                // 完整地址
                String formattedAddress = regeocodes.getString("formatted_address");
                // 省，市，区
                JSONObject addressComponent = regeocodes.getJSONObject("addressComponent");
                String province = "";
                String city = "";
                String district = "";
                if (addressComponent != null) {
                    province = addressComponent.getString(PaasConstant.PROVINCE);

                    Object cityObj = addressComponent.get(PaasConstant.CITY);
                    // 当城市是省直辖县时返回为空，以及城市为北京、上海、天津、重庆四个直辖市时，该字段返回为空
                    if (cityObj instanceof String) {
                        city = (String)cityObj;
                    }
                    district = addressComponent.getString(PaasConstant.DISTRICT);
                }

                JSONObject result = new JSONObject();
                result.put(PaasConstant.PROVINCE, province);
                result.put(PaasConstant.CITY, city);
                result.put(PaasConstant.DISTRICT, district);
                result.put(PaasConstant.ADDRESS, formattedAddress);
                return result;
            }

        } else {
            String info = respJson.getString("info");
            String msg = I18nMessageUtil.getMessage(I18nStringConstant.GAO_ERROR);
            if(!StringUtil.isEmpty(info)) {
                msg += info;
            }
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100043, msg);
        }

        return null;
    }

    /**
     * 通过高德restful api将详细地址信息转化为经纬度, 返回格式为JSON
     * @param address 详细地址
     * @param city 详细地址所在城市，为增加转换准确度
     * @return 返回一个json
     *
     * @author kaka
     * @date 2018-5-2
     * @since v3.21
     */
    public static JSONObject geo(String address, String city) throws XbbException {
        return geo(address, city, "JSON");
    }

    /**
     * 行政区域查询
     * @return
     * 创建时间 2021/8/17 9:26 AM
     * 修改时间 2021/8/17 9:26 AM
     * @author chy
     */
    public static JSONObject district() {
        Map<String, Object> geoParam = new HashMap<>();
        geoParam.put("key", ConfigConstant.GAODE_WEB_API_KEY);
        geoParam.put("subdistrict", 3);
        String respStr = OkHttpUtil.get(GAODE_DISTRICT_URL, geoParam);
        JSONObject addressJson = JSON.parseObject(respStr);
        return addressJson;
    }
}
